﻿using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace socketForm
{
    public partial class FrmServer : UIForm
    {
        List<Socket> clientProxySocketList = new List<Socket>();

        public FrmServer()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.txtIP.Text = SocketUtil.getIP();

        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            //1、创建socket
            Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            //2、绑定端口IP
            socket.Bind(new IPEndPoint(IPAddress.Parse(this.txtIP.Text), int.Parse(this.txtPort.Text)));
            //3、开始监听
            socket.Listen(10);//等待连接队列，同时来了100个连接请求，只能处理一个连接，队列里边放10个等待的连接，其他的返回错误消息
            //4、开始接受客户端连接
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptClientConnect),socket);
        }

        public void AcceptClientConnect(object socket)
        {
            var serverSocket = socket as Socket;
            this.AppendTextToTxtLog("服务器端开始接收客户端连接");
            while (true) {
                Socket proxySocket=null;
                try {
                    proxySocket = serverSocket.Accept();//阻塞当前线程，接收客户端的连接
                }
                catch (Exception ex) {
                    AppendTextToTxtLog("服务器监听失败，请重新开始");
                    return;
                }
 
                AppendTextToTxtLog(string.Format("客户端：{0}连接上了", proxySocket.RemoteEndPoint.ToString()));
                clientProxySocketList.Add(proxySocket);
                //不停的接收当前连接的客户端发送来的消息
                //ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), proxySocket);
                ThreadPool.QueueUserWorkItem(ReceiveData, proxySocket);//语法糖：可以简写
                //proxySocket.Receive();//阻塞当前线程，需要开一个线程执行
            }
            
        }

        //接收客户端的消息
        public void ReceiveData(object socket)
        {
            byte[] data = new byte[1024 * 1024];
            var proxySocket = socket as Socket;
            while (true)
            {
                int len = 0;

                try
                {
                    len = proxySocket.Receive(data, 0, data.Length, SocketFlags.None);
                }
                catch(Exception ex)
                {
                    //客户端异常退出
                    AppendTextToTxtLog(string.Format("客户端：{0}非正常退出", proxySocket.RemoteEndPoint.ToString()));
                    clientProxySocketList.Remove(proxySocket);//客户端socket列表中移除
                    stopConnect(proxySocket);  //关闭连接
                    return; //让方法结束，结束当前接收数据的异步线程
                }


                //接收到0个字节代表客户端正常退出
                if (len<=0) 
                {
                    //客户端正常退出
                    AppendTextToTxtLog(string.Format("客户端：{0}正常退出", proxySocket.RemoteEndPoint.ToString()));
                    clientProxySocketList.Remove(proxySocket);//客户端socket列表中移除
                    stopConnect(proxySocket);  //关闭连接
                    return; //让方法结束，结束当前接收数据的异步线程
                }

                //把接收到的数据放到文本框上
                string str = Encoding.UTF8.GetString(data,0,len);
                AppendTextToTxtLog(string.Format("接收到客户端：{0}的消息：{1}",proxySocket.RemoteEndPoint.ToString(),str));
            }
        }

        private void stopConnect(Socket proxySocket)
        {
            try
            {
                if (proxySocket.Connected)
                {
                    proxySocket.Shutdown(SocketShutdown.Both);
                    proxySocket.Close(100);

                }
            }
            catch (Exception ex)
            {

            }
        }

        //往日志文本框上添加数据
        public void AppendTextToTxtLog(string txt)
        {
            if (txtLog.InvokeRequired) //判断是否跨线程访问
            {
                //Invoke同步方法      BeginInvoke异步方法
                txtLog.Invoke(new Action<string>(s => {
                    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                }), txt);
            }
            else //本线程内访问
            {
                this.txtLog.Text = string.Format("{0}\r\n{1}", txt, txtLog.Text);
            }
            
        }

        /// <summary>
        /// 发送文字
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            foreach (var proxySocket in clientProxySocketList)
            {
                if (proxySocket.Connected)
                {
                    byte[] data = Encoding.UTF8.GetBytes(txtMsg.Text);
                    //添加头部一个字节消息类型 : 1文字    2闪屏    3文件
                    byte[] result  = new byte[data.Length+1];
                    result[0] = 1;
                    Buffer.BlockCopy(data, 0, result, 1, data.Length);
                    proxySocket.Send(result,0,result.Length,SocketFlags.None);
                }
            }
        }

        /// <summary>
        /// 发送闪屏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendShake_Click(object sender, EventArgs e)
        {
            foreach (var proxySocket in clientProxySocketList)
            {
                if (proxySocket.Connected)
                {
                    proxySocket.Send(new byte[]{2}, SocketFlags.None);
                }
            }
        }

        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            //读取要发送的文件数据
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() != DialogResult.OK) {
                    return;
                }
                //文件数据
                byte[] data = File.ReadAllBytes(ofd.FileName);
                //文件名数据：长度64
                byte[] nameData = new byte[64];
                byte[] temp = Encoding.UTF8.GetBytes(ofd.SafeFileName);
                Buffer.BlockCopy(temp, 0, nameData, 0, temp.Length);
                //数据包：1+64+文件数据字节数
                byte[] result = new byte[1+64+data.Length];
                result[0] = 3;
                Buffer.BlockCopy(nameData, 0, result, 1, nameData.Length);
                Buffer.BlockCopy(data, 0, result, 1+64, data.Length);
                string str = Encoding.UTF8.GetString(result);
                foreach (var proxySocket in clientProxySocketList)
                {
                    if (!proxySocket.Connected)
                    {
                        continue;
                    }
                    proxySocket.Send(result, SocketFlags.None);
                }
            }

        }
    }
}
